@@ -77,6 +77,7 @@ urlpatterns += [ |
||
| 77 | 77 |
# 支付相关 |
| 78 | 78 |
urlpatterns += [ |
| 79 | 79 |
url(r'^wx/order_create$', pay_views.wx_order_create_api, name='wx_order_create_api'), # 订单创建 |
| 80 |
+ url(r'^wx/order_query$', pay_views.wx_order_query_api, name='wx_order_query_api'), # 订单查询 |
|
| 80 | 81 |
url(r'^wx/notify_url$', pay_views.wx_notify_url_api, name='wx_notify_url_api'), # 支付异步通知回调地址 |
| 81 | 82 |
] |
| 82 | 83 |
|
@@ -0,0 +1,19 @@ |
||
| 1 |
+# -*- coding: utf-8 -*- |
|
| 2 |
+from __future__ import unicode_literals |
|
| 3 |
+ |
|
| 4 |
+from django.db import models, migrations |
|
| 5 |
+ |
|
| 6 |
+ |
|
| 7 |
+class Migration(migrations.Migration): |
|
| 8 |
+ |
|
| 9 |
+ dependencies = [ |
|
| 10 |
+ ('pay', '0001_initial'),
|
|
| 11 |
+ ] |
|
| 12 |
+ |
|
| 13 |
+ operations = [ |
|
| 14 |
+ migrations.AddField( |
|
| 15 |
+ model_name='orderinfo', |
|
| 16 |
+ name='trade_type', |
|
| 17 |
+ field=models.CharField(help_text='\u652f\u4ed8\u65b9\u5f0f', max_length=255, null=True, verbose_name='trade_type', blank=True), |
|
| 18 |
+ ), |
|
| 19 |
+ ] |
@@ -10,13 +10,26 @@ from pai2.basemodels import CreateUpdateMixin |
||
| 10 | 10 |
|
| 11 | 11 |
|
| 12 | 12 |
class OrderInfo(CreateUpdateMixin): |
| 13 |
+ """ |
|
| 14 |
+ # Trade State of Wechat Query |
|
| 15 |
+ SUCCESS ——— 支付成功 |
|
| 16 |
+ REFUND ——— 转入退款 |
|
| 17 |
+ NOTPAY ——— 未支付 |
|
| 18 |
+ CLOSED ——— 已关闭 |
|
| 19 |
+ REVOKED ——— 已撤销(刷卡支付) |
|
| 20 |
+ USERPAYING ——— 用户支付中 |
|
| 21 |
+ PAYERROR ——— 支付失败(其他原因,如银行返回失败) |
|
| 22 |
+ """ |
|
| 23 |
+ |
|
| 13 | 24 |
WAITING_PAY = 0 |
| 14 | 25 |
PAID = 1 |
| 15 |
- # DELETED = 2 |
|
| 26 |
+ FAIL = 2 |
|
| 27 |
+ # DELETED = 9 |
|
| 16 | 28 |
|
| 17 | 29 |
PAY_STATUS = ( |
| 18 | 30 |
(WAITING_PAY, u'待支付'), |
| 19 | 31 |
(PAID, u'已支付'), |
| 32 |
+ (FAIL, u'已失败'), |
|
| 20 | 33 |
# (DELETED, u'已删除'), |
| 21 | 34 |
) |
| 22 | 35 |
|
@@ -29,6 +42,8 @@ class OrderInfo(CreateUpdateMixin): |
||
| 29 | 42 |
body = models.CharField(_(u'body'), max_length=255, blank=True, null=True, help_text=u'商品描述') |
| 30 | 43 |
total_fee = models.IntegerField(_(u'total_fee'), default=0, help_text=u'总金额') |
| 31 | 44 |
|
| 45 |
+ trade_type = models.CharField(_('trade_type'), max_length=255, blank=True, null=True, help_text=u'支付方式')
|
|
| 46 |
+ |
|
| 32 | 47 |
pay_status = models.IntegerField(_(u'pay_status'), choices=PAY_STATUS, default=WAITING_PAY, help_text=u'支付状态', db_index=True) |
| 33 | 48 |
paid_at = models.DateTimeField(_(u'paid_at'), blank=True, null=True, help_text=_(u'支付时间')) |
| 34 | 49 |
|
@@ -45,7 +45,13 @@ def wx_order_create_api(request): |
||
| 45 | 45 |
wxpay = WeChatPay(wechat.get('appID'), wechat.get('apiKey'), wechat.get('mchID'))
|
| 46 | 46 |
|
| 47 | 47 |
# 生成订单 |
| 48 |
- order = OrderInfo.objects.create(from_uid=from_uid, to_lid=to_lid, to_uid=to_uid, total_fee=total_fee) |
|
| 48 |
+ order = OrderInfo.objects.create( |
|
| 49 |
+ from_uid=from_uid, |
|
| 50 |
+ to_lid=to_lid, |
|
| 51 |
+ to_uid=to_uid, |
|
| 52 |
+ total_fee=total_fee, |
|
| 53 |
+ trade_type=trade_type, |
|
| 54 |
+ ) |
|
| 49 | 55 |
|
| 50 | 56 |
try: |
| 51 | 57 |
prepay_data = wxpay.order.create( |
@@ -67,6 +73,8 @@ def wx_order_create_api(request): |
||
| 67 | 73 |
|
| 68 | 74 |
return JsonResponse({
|
| 69 | 75 |
'status': 200, |
| 76 |
+ 'message': 'Order Create Success', |
|
| 77 |
+ 'description': u'订单创建成功', |
|
| 70 | 78 |
'data': {
|
| 71 | 79 |
'order_id': order.order_id, |
| 72 | 80 |
'prepay_id': prepay_id, |
@@ -84,6 +92,75 @@ def order_paid_success(order): |
||
| 84 | 92 |
order.save() |
| 85 | 93 |
|
| 86 | 94 |
|
| 95 |
+def order_paid_fail(order): |
|
| 96 |
+ if order.pay_status == OrderInfo.FAIL: |
|
| 97 |
+ return |
|
| 98 |
+ |
|
| 99 |
+ order.pay_status = OrderInfo.FAIL |
|
| 100 |
+ order.save() |
|
| 101 |
+ |
|
| 102 |
+ |
|
| 103 |
+@logit |
|
| 104 |
+@transaction.atomic |
|
| 105 |
+def wx_order_query_api(request): |
|
| 106 |
+ """ |
|
| 107 |
+ 订单查询 |
|
| 108 |
+ :param request: |
|
| 109 |
+ :return: |
|
| 110 |
+ """ |
|
| 111 |
+ order_id = request.POST.get('order_id', '')
|
|
| 112 |
+ transaction_id = request.POST.get('transaction_id', '')
|
|
| 113 |
+ |
|
| 114 |
+ try: |
|
| 115 |
+ order = OrderInfo.objects.get(order_id=order_id) |
|
| 116 |
+ except OrderInfo.DoesNotExist: |
|
| 117 |
+ return response(OrderStatusCode.WX_ORDER_NOT_FOUND) |
|
| 118 |
+ |
|
| 119 |
+ if order.pay_status == OrderInfo.PAID: |
|
| 120 |
+ return JsonResponse({
|
|
| 121 |
+ 'status': 200, |
|
| 122 |
+ 'message': 'Order Pay Success', |
|
| 123 |
+ 'description': u'订单支付成功', |
|
| 124 |
+ 'data': {
|
|
| 125 |
+ |
|
| 126 |
+ } |
|
| 127 |
+ }) |
|
| 128 |
+ elif order.pay_status == OrderInfo.FAIL: |
|
| 129 |
+ return response(OrderStatusCode.WX_ORDER_PAY_FAIL) |
|
| 130 |
+ |
|
| 131 |
+ # 根据 trade_type 获取 wechat 配置 |
|
| 132 |
+ wechat = WECHAT.get(order.trade_type, {})
|
|
| 133 |
+ # WeChatPay 初始化 |
|
| 134 |
+ wxpay = WeChatPay(wechat.get('appID'), wechat.get('apiKey'), wechat.get('mchID'))
|
|
| 135 |
+ |
|
| 136 |
+ # 订单查询 |
|
| 137 |
+ query_data = wxpay.order.query(transaction_id, order_id) |
|
| 138 |
+ # 签名校验 |
|
| 139 |
+ if not wxpay.check_signature(query_data): |
|
| 140 |
+ return response(OrderStatusCode.SIGN_CHECK_FAIL) |
|
| 141 |
+ |
|
| 142 |
+ # 交易状态 |
|
| 143 |
+ trade_state = query_data.get('trade_state')
|
|
| 144 |
+ # 订单状态判断更新 |
|
| 145 |
+ if trade_state == 'SUCCESS': # 订单支付成功 |
|
| 146 |
+ order_paid_success(order) |
|
| 147 |
+ return JsonResponse({
|
|
| 148 |
+ 'status': 200, |
|
| 149 |
+ 'message': 'Order Pay Success', |
|
| 150 |
+ 'description': u'订单支付成功', |
|
| 151 |
+ 'data': {
|
|
| 152 |
+ |
|
| 153 |
+ } |
|
| 154 |
+ }) |
|
| 155 |
+ elif trade_state == 'NOTPAY': # 订单未支付 |
|
| 156 |
+ return response(OrderStatusCode.WX_ORDER_NOT_PAY) |
|
| 157 |
+ elif trade_state == 'USERPAYING': # 订单支付中 |
|
| 158 |
+ return response(OrderStatusCode.WX_ORDER_PAYING) |
|
| 159 |
+ else: # 订单支付失败 |
|
| 160 |
+ order_paid_fail(order) |
|
| 161 |
+ return response(OrderStatusCode.WX_ORDER_PAY_FAIL) |
|
| 162 |
+ |
|
| 163 |
+ |
|
| 87 | 164 |
@logit |
| 88 | 165 |
@transaction.atomic |
| 89 | 166 |
def wx_notify_url_api(request): |
@@ -98,6 +175,17 @@ def wx_notify_url_api(request): |
||
| 98 | 175 |
# 解析 XML 失败 |
| 99 | 176 |
return HttpResponse(settings.WXPAY_NOTIFY_FAIL) |
| 100 | 177 |
|
| 178 |
+ trade_type = data.get('trade_type', '')
|
|
| 179 |
+ |
|
| 180 |
+ # 根据 trade_type 获取 wechat 配置 |
|
| 181 |
+ wechat = WECHAT.get(trade_type, {})
|
|
| 182 |
+ # WeChatPay 初始化 |
|
| 183 |
+ wxpay = WeChatPay(wechat.get('appID'), wechat.get('apiKey'), wechat.get('mchID'))
|
|
| 184 |
+ |
|
| 185 |
+ # 签名校验 |
|
| 186 |
+ if not wxpay.check_signature(data): |
|
| 187 |
+ return response(OrderStatusCode.SIGN_CHECK_FAIL) |
|
| 188 |
+ |
|
| 101 | 189 |
out_trade_no = data.get('out_trade_no', '')
|
| 102 | 190 |
return_code = data.get('return_code', '')
|
| 103 | 191 |
result_code = data.get('result_code', '')
|
@@ -106,9 +194,9 @@ def wx_notify_url_api(request): |
||
| 106 | 194 |
return HttpResponse(settings.WXPAY_NOTIFY_FAIL) |
| 107 | 195 |
|
| 108 | 196 |
try: |
| 109 |
- order = OrderInfo.objects.get(order=out_trade_no) |
|
| 197 |
+ order = OrderInfo.objects.get(order_id=out_trade_no) |
|
| 110 | 198 |
except OrderInfo.DoesNotExist: |
| 111 |
- return HttpResponse(settings.WXPAY_NOTIFY_FAIL) |
|
| 199 |
+ return response(OrderStatusCode.WX_ORDER_NOT_FOUND) |
|
| 112 | 200 |
|
| 113 | 201 |
order_paid_success(order) |
| 114 | 202 |
|
@@ -64,6 +64,11 @@ class GroupPhotoStatusCode(BaseStatusCode): |
||
| 64 | 64 |
class OrderStatusCode(BaseStatusCode): |
| 65 | 65 |
""" 订单/支付相关错误码 4040xx """ |
| 66 | 66 |
WX_UNIFIED_ORDER_FAIL = StatusCodeField(404000, u'WX Unified Order Fail', description=u'微信统一下单失败') |
| 67 |
+ WX_ORDER_NOT_FOUND = StatusCodeField(404001, u'WX Order Not Found', description=u'订单不存在') |
|
| 68 |
+ WX_ORDER_NOT_PAY = StatusCodeField(404002, u'WX Order Not Pay', description=u'订单未支付') |
|
| 69 |
+ WX_ORDER_PAYING = StatusCodeField(404003, u'WX Order Paying', description=u'订单支付中') |
|
| 70 |
+ WX_ORDER_PAY_FAIL = StatusCodeField(404009, u'WX Order Pay Fail', description=u'微信支付失败') |
|
| 71 |
+ SIGN_CHECK_FAIL = StatusCodeField(404010, u'Sign Check Fail', description=u'签名校验失败') |
|
| 67 | 72 |
|
| 68 | 73 |
|
| 69 | 74 |
class MessageStatusCode(BaseStatusCode): |